#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define MAX 1024
#define ARG 64
#define SEP " "
int split(char *commandstr, char *argv[])
{
  assert(commandstr);
  assert(argv);

 argv[0] = strtok(commandstr, SEP);
 int i = 1;
 while((argv[i++] = strtok(NULL, SEP)));// 切失败的话，就代表赋值失败，返回0，循环退出

 return 0;
}

void showEnv()
{
  extern char **environ;
  for(int i = 0; environ[i]; i++) printf("%d:%s\n", i, environ[i]);
}

int main()
{
  int last_exit = 0;
  char myenv[32][256];
  int env_index = 0;
  while(1)
  {
    char commandstr[MAX] = {0};
    char* argv[ARG] = {NULL};

    printf("[kailin@mymachine currpath]# "); // 把currpath 换成 全局变量
    fflush(stdout);
    char *s = fgets(commandstr, sizeof(commandstr) - 1, stdin); // C 接口会自动在结尾出加上'\0',所以要预留出一个地方存放
    assert(s);
    (void)s;// 因为在release版本下，assert会自动关闭，而编译器对于没有使用的变量会告警，所以以强转来充当一次使用
    commandstr[strlen(commandstr) - 1] = '\0';
    // 特殊内键命令的处理

    int n = split(commandstr, argv);
    if(n != 0) continue;

    if(strcmp(argv[0], "cd") == 0)
    {
      if(argv[1] != NULL) chdir(argv[1]);
      continue;
    }
    else if(strcmp(argv[0], "export") == 0)
    {
      if(argv[1] != NULL)
      {
        strcpy(myenv[env_index], argv[1]); // 环境变量表是指针表，所以如果添加的环境变量被覆盖
        putenv(myenv[env_index++]);        // 则无法打印，因此需要有专门的缓冲区来保存
      }
      continue;
    }
    else if(strcmp(argv[0], "env") == 0)
    {
      showEnv();
      continue;
    }
    else if(strcmp(argv[0], "echo") == 0)
    {
      const char* target_env = NULL;
      if(argv[1][0] == '$')
      {
        if(argv[1][1] == '?')
        {
          printf("%d\n", last_exit);
          continue;
        }
        else
        {
          target_env = getenv(argv[1] + 1);
        }

        if(target_env == NULL) 
          printf("%s=%s\n", argv[1] + 1, target_env);
      }

      continue;
    }

    pid_t id = fork();
    assert(id >= 0);
    
    if(id == 0)
    {
      execvp(argv[0], argv);
      exit(0);
    }

    int status = 0;
    waitpid(id, &status, 0);
  }
  
  return 0;
}







